home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Sample Code / DTS.Lib & Samples / DTS.Draw / TRectObj.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-22  |  13.5 KB  |  463 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        TRectObj.c
  5. ** Written by:    Eric Soldan
  6. **
  7. ** Copyright © 1992 Apple Computer, Inc.
  8. ** All rights reserved.
  9. */
  10.  
  11. /* See the files "=How to write your app" and "=Using TreeObj.c" for information
  12. ** on this function. */
  13.  
  14. /* This file implements the messages for the rect object. */
  15.  
  16.  
  17.  
  18. /*****************************************************************************/
  19.  
  20.  
  21.  
  22. #include "App.h"            /* Get the application includes/typedefs, etc.    */
  23. #include "App.Common.h"        /* Get the stuff in common with rez.            */
  24. #include "App.protos.h"        /* Get the prototypes for the application.        */
  25.  
  26. #ifndef __OSEVENTS__
  27. #include <OSEvents.h>
  28. #endif
  29.  
  30. #ifndef __OSUTILS__
  31. #include <OSUtils.h>
  32. #endif
  33.  
  34. #ifndef __QUICKDRAW__
  35. #include <Quickdraw.h>
  36. #endif
  37.  
  38. #ifndef __STRING__
  39. #include <String.h>
  40. #endif
  41.  
  42. #ifndef __TREEOBJ2__
  43. #include "TreeObj2.h"
  44. #endif
  45.  
  46. #ifndef __UTILITIES__
  47. #include "Utilities.h"
  48. #endif
  49.  
  50.  
  51.  
  52. /**********************************************************************/
  53.  
  54.  
  55.  
  56. #pragma segment DrawObjects
  57. long    TRectObj(TreeObjHndl hndl, short message, long data)
  58. {
  59.     TreeObjHndl            root, shndl;
  60.     Rect                rct, oldRct, *rptr, grabber;
  61.     short                hit, fileRefNum, dx1, dx2, dy1, dy2, h, v, ptype;
  62.     short                fv, fh, flip;
  63.     Point                where, begMouse, curMouse, offset;
  64.     Boolean                selected;
  65.     EventRecord            option;
  66.     ClickInfo            *click;
  67.     RgnHandle            rgn;
  68.     OSErr                err;
  69. #if VH_VERSION
  70.     char                *cptr;
  71. #endif
  72.  
  73.     switch (message) {
  74.         case INITMESSAGE:
  75.                 /* This is called either with a sub-message of CREATEINIT or WINDOWINIT.
  76.                 ** The sub-message CREATEINIT is sent in when the object is initially created.
  77.                 ** The sub-message WINDOWINIT is sent in when the object belongs to a document
  78.                 ** that was just assigned to a window.  Note that the object could be created
  79.                 ** into a document that already has a window.  In this case, only the
  80.                 ** CREATEINIT sub-message will be received.  It is the object's responsibility
  81.                 ** to determine if the document has a window when CREATEINIT is called.
  82.                 ** An additional possible sub-message is NOWINDOWINIT.  In this case, the
  83.                 ** document is being disconnected from a window, and therefore objects have
  84.                 ** to convert back to their non-window state.  Both the WINDOWINIT and
  85.                 ** NOWINDOWINIT sub-messages would be application-specific, and sending
  86.                 ** the sub-messages to the objects would be the application's responsibility. */
  87.             break;
  88.  
  89.         case FREEMESSAGE:
  90.             if (mDerefCommon(hndl)->selected) {
  91.                 root = GetRootHndl(hndl);
  92.                 if ((*root)->type == ROOTOBJ)
  93.                     mDerefRoot(root)->numSelected--;
  94.                         /* Here the root object can be either the document root
  95.                         ** or the undo root.  The FREEOBJMESSAGE is due to the
  96.                         ** object being disposed of.  It may be being disposed of
  97.                         ** from either the document or undo side.  If it is being
  98.                         ** disposed of out of the undo side, we don't care about
  99.                         ** the selection status.  If it is being disposed of out
  100.                         ** of the document side, then we do care, as we will have
  101.                         ** one less selected object.  The numSelected count needs
  102.                         ** to reflect this. */
  103.             }
  104.             break;
  105.  
  106.         case COPYMESSAGE:
  107.                 /* CopyOneChild was called (indirectly) and an object has been
  108.                 ** cloned.  At this point the data area has already been copied.
  109.                 ** If the data area holds references to other handles, these
  110.                 ** handles need to be copied so that the object has its own copies.
  111.                 ** Since the data was copied from the original child, the fields
  112.                 ** holding references to handles actually contain the same reference
  113.                 ** that the original child contains.  To create unique handles for
  114.                 ** the copy, this object should pass itself an INITOBJMESSAGE to
  115.                 ** initially create unique handles for the copy.
  116.                 ** The data parameter for this message is the handle of the object
  117.                 ** that was copied.  It is possible that the copy won't be an exact
  118.                 ** copy, and that there should be some differences between the
  119.                 ** original and the copy.  By having a reference to the original,
  120.                 ** these situations can be resolved. */
  121.             break;
  122.  
  123.         case UNDOMESSAGE:
  124.             root  = GetRootHndl(hndl);
  125.             if ((*root)->type == ROOTOBJ) {
  126.                 ptype = (*((*hndl)->parent))->type;
  127.                 switch (data) {
  128.                     case UNDOFROMDOC:
  129.                         if (mDerefCommon(hndl)->selected == true) {
  130.                             mDerefCommon(hndl)->selected = false;
  131.                             mDerefRoot(root)->numSelected--;
  132.                         }        /* If a selected object is moving from the document into the */
  133.                         break;    /* undo, reflect this in the numSelected count in the root.  */
  134.  
  135.                     case UNDOTODOC:
  136.                         mDerefCommon(hndl)->selected = false;
  137.                         if (ptype != GROUPOBJ) {
  138.                             mDerefCommon(hndl)->selected = true;
  139.                             mDerefRoot(root)->numSelected++;
  140.                         }        /* An object moving into the document needs to be selected
  141.                                 ** so the user can see what changed.  The select status while
  142.                                 ** in the undo doesn't matter, as the user can't see what is in
  143.                                 ** the undo. */
  144.                         break;
  145.                 }
  146.             }
  147.             break;
  148.  
  149.         case CONVERTMESSAGE:
  150.                 /* This is called to convert any data that loses meaning when saved.
  151.                 ** It is called with a TOFILE or a FROMFILE sub-message.
  152.                 **
  153.                 ** For the CONVERTTOID sub-message:
  154.                 **
  155.                 ** If this object has any references to handles elsewhere in the document,
  156.                 ** these references lose meaning when saved to disk.  When the file is
  157.                 ** read in, the handle references will not coorelate to what is currently
  158.                 ** in ram.
  159.                 ** Prior to starting a file save, all of the objects in the tree are
  160.                 ** assigned sequential id numbers.  You can replace handle references
  161.                 ** with the 4-byte treeID.  To convert the handle to a treeID, just
  162.                 ** do something like the following:
  163.                 **     Hndl2ID(&DerefMyObject(hndl)->thingToConvert);
  164.                 **
  165.                 ** For the CONVERTTOHNDL sub-message:
  166.                 **
  167.                 ** Once the file is opened and completely loaded into ram, there may be
  168.                 ** objects that have references to elsewhere in the file that were stored
  169.                 ** as treeID's.  These need to be converted back to handle references.
  170.                 ** To do this, do something like the below:
  171.                 **      ID2Hndl(hndl, &DerefMyObject(hndl)->thingToConvert);
  172.                 */
  173.             break;
  174.  
  175.         case FREADMESSAGE:
  176.             fileRefNum = data;
  177.             err = ReadTreeObjData(hndl, fileRefNum);
  178.             mDerefCommon(hndl)->selected = false;
  179.             return(err);
  180.             break;
  181.  
  182.         case FWRITEMESSAGE:
  183.             fileRefNum = data;
  184.             return(WriteTreeObjData(hndl, fileRefNum));
  185.             break;
  186.  
  187.         case HREADMESSAGE:
  188.         case HWRITEMESSAGE:
  189.             break;
  190.  
  191.         case HITTESTMESSAGE:
  192.             click = (ClickInfo *)data;
  193.             rct   = mDerefCommon(hndl)->rect;
  194.             where = click->localEvent.where;
  195.             hit   = 0;
  196.             switch (click->message) {
  197.                 case HITTESTOBJ:
  198.                     if (PtInRect(where, &rct)) {
  199.                         rgn = (RgnHandle)DoTreeObjMethod(hndl, GETRGNMESSAGE, 0);
  200.                         if (PtInRgn(where, rgn))
  201.                             hit = -1;
  202.                         DisposeRgn(rgn);
  203.                     }
  204.                     break;
  205.                 case HITTESTGRABBER:
  206.                     if (mDerefCommon(hndl)->selected) {
  207.                         grabber = rct;
  208.                         InsetRect(&grabber, -4, -4);
  209.                         if (PtInRect(where, &grabber)) {
  210.                             GetMouse(&curMouse);
  211.                             for (;;) {
  212.                                 if (where.v < (rct.top + 4)) {
  213.                                     if (where.h <  (rct.left + 4) ) {
  214.                                         hit = 1;
  215.                                         flip = (VFLIPOBJ | HFLIPOBJ);
  216.                                         where.h  = rct.right;
  217.                                         where.v  = rct.bottom;
  218.                                         offset.h = rct.left - curMouse.h;
  219.                                         offset.v = rct.top  - curMouse.v;
  220.                                         break;
  221.                                     }
  222.                                     if (where.h >= (rct.right - 4)) {
  223.                                         hit = 2;
  224.                                         flip = VFLIPOBJ;
  225.                                         where.h  = rct.left;
  226.                                         where.v  = rct.bottom;
  227.                                         offset.h = rct.right - curMouse.h;
  228.                                         offset.v = rct.top   - curMouse.v;
  229.                                         break;
  230.                                     }
  231.                                 }
  232.                                 if (where.v >= (rct.bottom - 4)) {
  233.                                     if (where.h <  (rct.left + 4) ) {
  234.                                         hit = 3;
  235.                                         flip = HFLIPOBJ;
  236.                                         where.h  = rct.right;
  237.                                         where.v  = rct.top;
  238.                                         offset.h = rct.left   - curMouse.h;
  239.                                         offset.v = rct.bottom - curMouse.v;
  240.                                         break;
  241.                                     }
  242.                                     if (where.h >= (rct.right - 4)) {
  243.                                         hit = 4;
  244.                                         flip = 0;
  245.                                         where.h  = rct.left;
  246.                                         where.v  = rct.top;
  247.                                         offset.h = rct.right  - curMouse.h;
  248.                                         offset.v = rct.bottom - curMouse.v;
  249.                                         break;
  250.                                     }
  251.                                 }
  252.                                 break;
  253.                             }
  254.                         }
  255.                     }
  256.                     break;
  257.                 case CANBETARGET:
  258.                     return(false);
  259.                     break;
  260.                 case CANTAKEKEYS:
  261.                     return(false);
  262.                     break;
  263.             }
  264.             if (hit) {
  265.                 for (; (*(root = (*hndl)->parent))->type != ROOTOBJ; hndl = root);
  266.                     /* Group objects can not be hit directly.  Only the base
  267.                     ** objects can be hit.  However, if a base object is hit,
  268.                     ** we want to return the top-most group object that
  269.                     ** contains it.  Walk the tree up until the root object
  270.                     ** is hit.  The object below this is top-most group object,
  271.                     ** or the base object doesn't belong to a group. */
  272.                 if (click->message == HITTESTGRABBER) {
  273.                     if (mDerefRoot(root)->numSelected == 1) {
  274.                         click->localEvent.where = where;
  275.                         click->offset           = offset;
  276.                         click->oldFlip = click->newFlip = flip;
  277.                     }
  278.                     else hit = 0;
  279.                 }
  280.             }
  281.             if (!hit)
  282.                 hndl = nil;
  283.             click->grabber = hit;
  284.             return((long)hndl);
  285.             break;
  286.  
  287.         case GETRGNMESSAGE:
  288.             rgn = NewRgn();
  289.             rct = mDerefCommon(hndl)->rect;
  290.             RectRgn(rgn, &rct);
  291.             return((long)rgn);
  292.             break;
  293.  
  294.         case GETBBOXMESSAGE:
  295.             rptr  = (Rect *)data;
  296.             *rptr = mDerefCommon(hndl)->rect;
  297.             break;
  298.  
  299.         case SETBBOXMESSAGE:
  300.             rptr = (Rect *)data;
  301.             mDerefCommon(hndl)->rect = *rptr;
  302.             break;
  303.  
  304.         case SECTBBOXMESSAGE:
  305.             rptr = (Rect *)data;
  306.             SectRect(rptr, &(mDerefCommon(hndl)->rect), &rct);
  307.             if (!EmptyRect(&rct)) return(true);
  308.             break;
  309.  
  310.         case TARGETMESSAGE:
  311.             break;
  312.  
  313.         case DRAWMESSAGE:
  314.             rct = mDerefCommon(hndl)->rect;
  315.             switch (data) {
  316.                 case DRAWOBJ:
  317.                     FillRect(&rct, &qd.white);
  318.                     FrameRect(&rct);
  319.                     break;
  320.                 case ERASEOBJ:
  321.                     EraseRect(&rct);
  322.                     break;
  323.                 case DRAWSELECT:
  324.                     if (mDerefCommon(hndl)->selected) {
  325.                         for (h = v = 1; (h > -1); h -= (v ^= 1)) {
  326.                             grabber.top  = v ? rct.top  : rct.bottom;
  327.                             grabber.left = h ? rct.left : rct.right;
  328.                             grabber.bottom = (grabber.top  -= 3) + 6;
  329.                             grabber.right  = (grabber.left -= 3) + 6;
  330.                             InvertRect(&grabber);
  331.                         }
  332.                     }
  333.                     break;
  334.                 case DRAWGHOST:
  335.                     PenMode(patXor);
  336.                     FrameRect(&rct);
  337.                     PenNormal();
  338.                     break;
  339.                 case DRAWMASK:
  340.                     FillRect(&rct, &qd.black);
  341.                     break;
  342.             }
  343.             break;
  344.  
  345.         case PRINTMESSAGE:
  346.             DoTreeObjMethod(hndl, DRAWMESSAGE, DRAWOBJ);
  347.             break;
  348.  
  349. #if VH_VERSION
  350.         case VHMESSAGE:
  351.             cptr = ((VHFormatDataPtr)data)->data;
  352.             ccatchr(cptr, 13, 2);
  353.             ccat   (cptr, "$10: TRectObj:");
  354.             ccatchr(cptr, 13, 1);
  355.             ccat   (cptr, "  $00: selected = ");
  356.             ccatdec(cptr, mDerefRect(hndl)->selected);
  357.             ccatchr(cptr, 13, 1);
  358.             rct = mDerefRect(hndl)->rect;
  359.             ccat   (cptr, "  $02: rect     = ($");
  360.             ccathex(cptr, 0, 4, 4, rct.top);
  361.             ccat   (cptr, ",$");
  362.             ccathex(cptr, 0, 4, 4, rct.left);
  363.             ccat   (cptr, ",$");
  364.             ccathex(cptr, 0, 4, 4, rct.bottom);
  365.             ccat   (cptr, ",$");
  366.             ccathex(cptr, 0, 4, 4, rct.right);
  367.             ccat   (cptr, ")");
  368.             return(true);
  369.             break;
  370. #endif
  371.  
  372. /* End of standard messages.  Start of object-specific messages. */
  373.  
  374.         case CLICKMESSAGE:
  375.             click = (ClickInfo *)data;
  376.             switch (click->message) {
  377.                 case CLICKSELECT:
  378.                     for (shndl = hndl; (*(root = (*shndl)->parent))->type != ROOTOBJ; shndl = root);
  379.                     selected = mDerefCommon(shndl)->selected;
  380.                     if ((!selected) || (click->localEvent.modifiers & shiftKey)) {
  381.                         if (shndl == hndl)
  382.                             DoTreeObjMethod(hndl, SETSELECTMESSAGE, SELECTTOGGLE);
  383.                                 /* If the object doesn't belong to a group, then we want to change
  384.                                 ** the select status.  If it belongs to a group, the group object
  385.                                 ** is responsible for maintaining the select status. */
  386.                     }
  387.                     break;
  388.                 case CLICKDRAG:
  389.                     OffsetRect(&(mDerefCommon(hndl)->rect), click->offset.h, click->offset.v);
  390.                     break;
  391.             }
  392.             break;
  393.  
  394.         case KEYMESSAGE:
  395.             break;
  396.  
  397.         case SETSELECTMESSAGE:
  398.             selected = mDerefCommon(hndl)->selected;
  399.             if (selected != data) {        /* The select status is other than desired. */
  400.                 mDerefCommon(hndl)->selected = true;
  401.                 DoTreeObjMethod(hndl, DRAWMESSAGE, DRAWSELECT);
  402.                     /* Force a draw-toggle of the selection grabbers. */
  403.                 mDerefCommon(hndl)->selected = (selected ^= true);
  404.                 root = GetRootHndl(hndl);
  405.                 if (selected)
  406.                     mDerefRoot(root)->numSelected++;
  407.                 else
  408.                     mDerefRoot(root)->numSelected--;
  409.                         /* Change the global numSelected value to reflect the new
  410.                         ** number of selected objects. */
  411.             }
  412.             break;
  413.  
  414.         case GETSELECTMESSAGE:
  415.             return(mDerefCommon(hndl)->selected);
  416.             break;
  417.  
  418.         case SIZEMESSAGE:
  419.             DoTreeObjMethod(hndl, GETBBOXMESSAGE, (long)&oldRct);
  420.             click    = (ClickInfo *)data;
  421.             begMouse = click->localEvent.where;
  422.             GetMouse(&curMouse);
  423.             curMouse.h += click->offset.h;
  424.             curMouse.v += click->offset.v;
  425.             dx1 = dx2 = (curMouse.h - begMouse.h);
  426.             dy1 = dy2 = (curMouse.v - begMouse.v);
  427.             if (dx2 < 0)
  428.                 dx2 = -dx2;
  429.             if (dy2 < 0)
  430.                 dy2 = -dy2;
  431.             OSEventAvail(nullEvent, &option);
  432.             if (option.modifiers & shiftKey) {
  433.                 if (dx2 > dy2)
  434.                     dx2 = dy2;
  435.                 else
  436.                     dy2 = dx2;
  437.             }
  438.             if (dx1 < 0)
  439.                 dx2 = -dx2;
  440.             if (dy1 < 0)
  441.                 dy2 = -dy2;
  442.             curMouse.h = begMouse.h + dx2;
  443.             curMouse.v = begMouse.v + dy2;
  444.             fv = (curMouse.v < begMouse.v) ? VFLIPOBJ : 0x00;
  445.             fh = (curMouse.h < begMouse.h) ? HFLIPOBJ : 0x00;
  446.             rct.top    = (fv) ? curMouse.v : begMouse.v;
  447.             rct.bottom = (fv) ? begMouse.v : curMouse.v;
  448.             rct.left   = (fh) ? curMouse.h : begMouse.h;
  449.             rct.right  = (fh) ? begMouse.h : curMouse.h;
  450.             mDerefCommon(hndl)->rect = rct;
  451.             click->oldFlip = click->newFlip;
  452.             click->newFlip = (fv | fh);
  453.             return(!EqualRect(&rct, &oldRct));
  454.             break;
  455.  
  456.     }
  457.  
  458.     return(noErr);
  459. }
  460.  
  461.  
  462.  
  463.